package com.alibaba.citrus.ots.price.ability.facade;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.platform.enhance.repository.CustomerAddressRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.CustomerRepository;
import com.alibaba.citrus.ots.price.ability.functions.PlatformCodeFlagEnum;
import com.alibaba.citrus.ots.price.ability.functions.entity.price.PriceEntity;
import com.alibaba.citrus.ots.price.ability.functions.factory.price.PriceFactory;
import com.alibaba.citrus.ots.price.ability.functions.factory.price.process.PropertyProcessManager;
import com.alibaba.citrus.ots.price.repository.PriceQueryRepository;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcots.model.dto.*;
import com.epoch.app.bcots.service.BaseDataService;
import com.epoch.app.bcots.service.BcOtsService;
import com.epoch.app.otsplatformenhance.domain.customeraddress.model.CustomerAddress;
import com.epoch.app.otsplatformenhance.dto.request.CustomerBatchRequest;
import com.epoch.app.otsplatformenhance.enums.RoleCodeEnum;
import com.epoch.app.otsplatformenhance.sdo.CustomerSDO;
import com.epoch.app.otspricecenter.api.pricequery.dto.PageQueryItemForDropBoxRequest;
import com.epoch.app.otspricecenter.api.pricequery.service.PriceQueryService;
import com.epoch.app.otspricecenter.dto.request.*;
import com.epoch.app.otspricecenter.dto.response.ItemPriceResponse;
import com.epoch.app.otspricecenter.dto.response.PriceQueryResponse;
import com.epoch.app.otspricecenter.enums.DimensionPropertyEnum;
import com.epoch.app.otspricecenter.model.dto.CustomerItemPriceRequest;
import com.epoch.app.otspricecenter.model.dto.CustomerItemPriceResponse;
import com.epoch.app.otspricecenter.model.dto.DropBox;
import com.epoch.app.otspricecenter.model.dto.PageQueryPriceResponse;
import com.epoch.app.otspricecenter.model.dto.PriceCategorySDOList;
import com.epoch.app.otspricecenter.model.dto.PriceDimensionRequest;
import com.epoch.app.otspricecenter.model.dto.RegularPriceRequest;
import com.epoch.app.otspricecenter.model.dto.RegularPriceResponse;
import com.epoch.app.otspricecenter.model.dto.TypeAndDimensionTree;
import com.epoch.app.otspricecenter.model.enums.PriceTypeEnum;
import com.epoch.app.otspricecenter.sdo.PriceDimensionSDO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

/**
 * @author hanguo
 * @date 2021/9/13
 */
@Primary
@Service
public class PriceQueryServiceImpl implements PriceQueryService {

    private static Log log = Log.getLogger(PriceQueryServiceImpl.class);

    @Resource
    private PriceQueryRepository priceQueryRepository;

    @Resource
    private BaseDataService baseDataService;

    @Resource
    private ApplicationContext applicationContext;

    @Autowired
    private BcOtsService bcOtsService;

    @Resource
    private CustomerAddressRepository customerAddressRepository;

    @Resource
    private CustomerRepository customerRepository;

    @Resource
    private PropertyProcessManager propertyProcessManager;


    @Override
    @FacadeInvoker(value = "价格列表查询", errorCode = "OTS-07-006-01-16-001")
    public Result<List<PageQueryPriceResponse>> queryPricePageList(PageQueryPriceRequest pageQueryPriceRequest) {

        // 控制角色
        EmployeeGetCurrentLoginResponse currentLoginEmployeeRoles = bcOtsService.employeeGetCurrentLogin();
        if (currentLoginEmployeeRoles != null && StringUtils.isNotBlank(currentLoginEmployeeRoles.getRoleCodes())){
            String roleCodes = currentLoginEmployeeRoles.getRoleCodes();
            if (StringUtils.isBlank(roleCodes) || "[]".equals(roleCodes)){
                return Result.success(new ArrayList<>());
            }
            List<String> noPermissionRoleCodeList = Lists.newArrayList(RoleCodeEnum.SALE_MAN.getCode(), RoleCodeEnum.DEPARTMENT_MANAGER.getCode());
            String newRoleCodes = roleCodes.replaceAll(" ", "");
            List<String> roles = com.alibaba.acm.shaded.com.google.common.collect.Lists.newArrayList(newRoleCodes.substring(1, newRoleCodes.length() - 2).split(","));
            boolean permission = false;
            for (String role : roles) {
                if (!noPermissionRoleCodeList.contains(role)) {
                    permission = true;
                    break;
                }
            }
            if (!permission){
                return Result.success(new ArrayList<>());
            }
        }
        return queryPricePageListFromES(pageQueryPriceRequest);

    }

    @Override
    public Result<List<PageQueryPriceResponse>> queryPricePageListFromES(PageQueryPriceRequest pageQueryPriceRequest) {
        return priceQueryRepository.queryPricePageListFromES(pageQueryPriceRequest);
    }

    @FacadeInvoker(value = "价格类型类目树查询", errorCode = "OTS-07-006-01-16-003")
    @Override
    public Result<TypeAndDimensionTree> getTypeAndDimensionTree() {
        //List<PriceCategorySDO>>   Map<String,PriceCategorySDOList>
        Map<String, PriceCategorySDOList> typeAndDimensionTreeMap = Maps.newHashMap();
        priceQueryRepository.getTypeAndDimensionTree().getResult().forEach((k, v) -> {
            PriceCategorySDOList priceCategorySDOList = new PriceCategorySDOList();
            priceCategorySDOList.setList(v);
            typeAndDimensionTreeMap.put(k, priceCategorySDOList);
        });
        TypeAndDimensionTree typeAndDimensionTree = new TypeAndDimensionTree();
        typeAndDimensionTree.setMap(typeAndDimensionTreeMap);
        Result result = new Result();
        result.setResult(typeAndDimensionTree);
        return result;
    }

    @Override
    public Result<List<DropBox>> pageQueryItemForDropBox(PageQueryItemForDropBoxRequest pageQueryItemForDropBoxRequest) {
        BaselineQueryScItemByPageRequest baselineQueryScItemByPageRequest = new BaselineQueryScItemByPageRequest();
        baselineQueryScItemByPageRequest.setStart(pageQueryItemForDropBoxRequest.getStart());
        baselineQueryScItemByPageRequest.setLimit(pageQueryItemForDropBoxRequest.getLimit());
        baselineQueryScItemByPageRequest.setTitle(pageQueryItemForDropBoxRequest.getName());
        Object scItemByPage = baseDataService.baselineQueryScItemByPage(baselineQueryScItemByPageRequest);
        if(Objects.isNull(scItemByPage)){
            return Result.success(new ArrayList<>());
        }
        Map<String,Object> scItemByPageMap = (Map<String, Object>) scItemByPage;

        Map<String,Object> resultMap = (Map<String, Object>) scItemByPageMap.get("result");
        if(MapUtils.isEmpty(resultMap)){
            return Result.success(new ArrayList<>());
        }

        Map<String,Object> resultSubMap =(Map<String,Object>) resultMap.get("result");
        if(MapUtils.isEmpty(resultSubMap)){
            return Result.success(new ArrayList<>());
        }

        List<Map<String,String>> searchResult = (List<Map<String, String>>) resultSubMap.get("searchResult");
        if(CollectionUtils.isEmpty(searchResult)){
            return Result.success(new ArrayList<>());
        }

        List<DropBox> dropBoxes = searchResult.stream().map(item -> {
            DropBox dropBox = new DropBox();
            dropBox.setCode(item.get("outerId"));
            dropBox.setName(item.get("title"));
            return dropBox;
        }).collect(Collectors.toList());
        Result<List<DropBox>> result = Result.success(dropBoxes);
        result.setTotal(((Double) resultSubMap.get("total")).intValue());
        return result;
    }

    /**
     * 价格查询_有转码功能的接口 内部->外部
     *
     * @param priceQueryRequest
     * @return
     */
    @FacadeInvoker(remark = "价格查询")
    @Override
    public Result<PriceQueryResponse> batchQueryPriceExpand(PriceQueryRequest priceQueryRequest) {
        log.info("当前查询价格入参 = {}", JSONObject.toJSONString(priceQueryRequest));

        Result<PriceQueryResponse> priceQueryResponseResult = null;
        if (Objects.isNull(priceQueryRequest) || MapUtils.isEmpty(priceQueryRequest.getFeatures())
                || StringUtils.isBlank((CharSequence) priceQueryRequest.getFeatures().get("codeFlag"))) {
            log.error("请传编码转换标识，内部转外部:inner_code_to_out_code,外部转内部:out_code_to_inner_code = {}",
                    JSONObject.toJSONString(priceQueryRequest));
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            throw new FacadeException("OTS-07-006-01-15-008");
        }

        paramTrim(priceQueryRequest);

        if (PlatformCodeFlagEnum.OUT_CODE_TO_INNER_CODE.getCode().equals(priceQueryRequest.getFeatures().get("codeFlag"))) {
            priceQueryResponseResult = batchQueryPrice(priceQueryRequest);
            return priceQueryResponseResult;
        }

        if (!PlatformCodeFlagEnum.INNER_CODE_TO_OUT_CODE.getCode().equals(priceQueryRequest.getFeatures().get("codeFlag"))) {
            log.error("请传正确的编码转换标识，内部转外部:inner_code_to_out_code,外部转内部:out_code_to_inner_code = {}",
                    JSONObject.toJSONString(priceQueryRequest));
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            throw new FacadeException("OTS-07-006-01-15-009");
        }


        //获取物料编码内外部映射关系
        List<ScItemSDO> scItemSDOS = obtainItemMap(priceQueryRequest, true);
        Map<String, String> materialInnerAndOuterCodeMap = scItemSDOS.stream().collect(Collectors.toMap(ScItemSDO::getScItemId, ScItemSDO::getOuterId));
        Map<String, String> materialOuterAndInnerCodeMap = scItemSDOS.stream().collect(Collectors.toMap(ScItemSDO::getOuterId, ScItemSDO::getScItemId));

        //获取销售组织编码的对应关系（内部编码:外部编码）
        Map<String, String> orgSalesOrganizationInnerAndOuterCodeMap = obtainSalesOrganizationMap(priceQueryRequest);

        //获取销售渠道编码的对应关系（内部编码:外部编码）
        Map<String, String> channelCodeMap = obtainChannelMap(priceQueryRequest);


        //重新构建查询参数
        List<DimensionPropertyInfoRequest> conversionRequest = Lists.newArrayList();
        //销售组织、渠道、物料编码转换
        for (DimensionPropertyInfoRequest item : priceQueryRequest.getDimensionPropertyInfoRequestList()) {
            DimensionPropertyInfoRequest dimensionPropertyInfoRequest = new DimensionPropertyInfoRequest();
            BeanUtils.copyProperties(item, dimensionPropertyInfoRequest);

            //内部编码转外部编码
            String innerMaterialCode = item.getMaterialInfoRequest().getMaterialCode();
            if (StringUtils.isBlank(innerMaterialCode)) {
                log.error("物料编码不能为空 = {}", item);
                log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                throw new FacadeException("OTS-07-006-01-15-006");
            }
            MaterialInfoRequest materialInfoRequest = new MaterialInfoRequest();
            BeanUtils.copyProperties(item.getMaterialInfoRequest(), materialInfoRequest);
            //物料编码转换
            String outerMaterialCode = materialInnerAndOuterCodeMap.get(innerMaterialCode);
            if (StringUtils.isBlank(outerMaterialCode)) {
                log.error("未查询到物料编码内外部映射关系，请检查 = {}", item);
                log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                throw new FacadeException("OTS-07-005-01-16-004");
            }
            materialInfoRequest.setMaterialCode(outerMaterialCode);
            dimensionPropertyInfoRequest.setMaterialInfoRequest(materialInfoRequest);

            PlaceInfoRequest placeInfoRequest = new PlaceInfoRequest();
            BeanUtils.copyProperties(item.getPlaceInfoRequest(), placeInfoRequest);
            //渠道转换
            String innerChannelCode = item.getPlaceInfoRequest().getChannelCode();
            if (StringUtils.isNotBlank(innerChannelCode)) {
                String channelCode = channelCodeMap.get(innerChannelCode.trim());
                if (StringUtils.isBlank(channelCode)) {
                    log.error("查询的渠道不存在，请检查是否存在映射关系 = {}", item);
                    log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                    throw new FacadeException("OTS-07-005-01-16-003");
                }
                placeInfoRequest.setChannelCode(channelCode);
            }

            //销售部门转换
            String innerSalesDepartment = item.getPlaceInfoRequest().getSalesDepartment();
            if (StringUtils.isNotBlank(innerSalesDepartment)) {
                String salesDepartment = orgSalesOrganizationInnerAndOuterCodeMap.get(innerSalesDepartment);
                if (StringUtils.isBlank(salesDepartment)) {
                    log.info("查询的销售部门不存在，请检查是否存在映射关系 = {}",item);
                    log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                    throw new FacadeException("OTS-07-005-01-16-005");
                }
                placeInfoRequest.setSalesDepartment(salesDepartment);
            }
            //销售组织转换
            String innerSalesGroup = item.getPlaceInfoRequest().getSalesGroup();
            if (StringUtils.isNotBlank(innerSalesGroup)) {
                String salesGroup = orgSalesOrganizationInnerAndOuterCodeMap.get(innerSalesGroup);
                if (StringUtils.isBlank(salesGroup)) {
                    log.info("查询的销售组不存在，请检查是否存在映射关系 = {}",item);
                    log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                    throw new FacadeException("OTS-07-005-01-16-006");
                }
                placeInfoRequest.setSalesGroup(salesGroup);
            }

            //销售组织转换
            String innerOrgSalesOrganizationCode = item.getPlaceInfoRequest().getOrgSalesOrganizationCode();
            if (StringUtils.isBlank(innerOrgSalesOrganizationCode)) {
                if (StringUtils.isBlank(innerMaterialCode)) {
                    log.info("销售组织编码不能为空 = {}", item);
                    log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                    throw new FacadeException("OTS-07-006-01-15-007");
                }
            }
            String outerOrgSalesOrganizationCode = orgSalesOrganizationInnerAndOuterCodeMap.get(item.getPlaceInfoRequest().
                    getOrgSalesOrganizationCode());
            if (StringUtils.isBlank(outerOrgSalesOrganizationCode)) {
                log.error("未查询到销售组织编码内外部映射关系，请检查 = {}", JSONObject.toJSONString(item));
                log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
                throw new FacadeException("OTS-07-005-01-16-002");
            }
            placeInfoRequest.setOrgSalesOrganizationCode(outerOrgSalesOrganizationCode);
            dimensionPropertyInfoRequest.setPlaceInfoRequest(placeInfoRequest);

            conversionRequest.add(dimensionPropertyInfoRequest);

        }

        priceQueryRequest.setDimensionPropertyInfoRequestList(conversionRequest);
        priceQueryResponseResult = applicationContext.getBean(PriceQueryServiceImpl.class)
                .batchQueryPrice(priceQueryRequest);

        //货品编码转换外部转内部
        PriceQueryResponse priceQueryResponse = priceQueryResponseResult.getResult();
        List<ItemPriceResponse> itemPriceResponseList = Lists.newArrayList();
        for (ItemPriceResponse itemPriceResponse : priceQueryResponse.getItemPriceResponseList()) {
            ItemPriceResponse response = new ItemPriceResponse();
            BeanUtils.copyProperties(itemPriceResponse, response);
            response.setItemId(materialOuterAndInnerCodeMap.get(itemPriceResponse.getItemId()));
            itemPriceResponseList.add(response);
        }
        priceQueryResponse.setItemPriceResponseList(itemPriceResponseList);
        priceQueryResponseResult.setResult(priceQueryResponse);

        return priceQueryResponseResult;
    }

    /**
     * 数据转换
     * @param priceQueryRequest
     * @param newPriceQueryRequest
     */
    private void copyValue(PriceQueryRequest priceQueryRequest, PriceQueryRequest newPriceQueryRequest) {
        List<DimensionPropertyInfoRequest> newDimensionPropertyInfoRequestList = Lists.newArrayList();
        newPriceQueryRequest.setFeatures(priceQueryRequest.getFeatures());
        priceQueryRequest.getDimensionPropertyInfoRequestList().forEach(e->{
            DimensionPropertyInfoRequest newDimensionPropertyInfoRequest = new DimensionPropertyInfoRequest();
            newDimensionPropertyInfoRequest.setPriceTypeId(e.getPriceTypeId());
            newDimensionPropertyInfoRequest.setPriceUseDate(e.getPriceUseDate());

            MaterialInfoRequest newMaterialInfoRequest = new MaterialInfoRequest();
            newMaterialInfoRequest.setMaterialCode(e.getMaterialInfoRequest().getMaterialCode());
            newMaterialInfoRequest.setScItemGroupCode(e.getMaterialInfoRequest().getScItemGroupCode());
            newMaterialInfoRequest.setItemInfoFeatures(e.getMaterialInfoRequest().getItemInfoFeatures());
            newDimensionPropertyInfoRequest.setMaterialInfoRequest(newMaterialInfoRequest);

            HumanInfoRequest newHumanInfoRequest = new HumanInfoRequest();
            newHumanInfoRequest.setCustomerCode(e.getHumanInfoRequest().getCustomerCode());
            newHumanInfoRequest.setCustomerGroup(e.getHumanInfoRequest().getCustomerGroup());
            newHumanInfoRequest.setCustomerSendAddressCode(e.getHumanInfoRequest().getCustomerSendAddressCode());
            newHumanInfoRequest.setCustomerSaleAddressCode(e.getHumanInfoRequest().getCustomerSaleAddressCode());
            newHumanInfoRequest.setPriceListCode(e.getHumanInfoRequest().getPriceListCode());
            newHumanInfoRequest.setHumanInfoFeatures(e.getHumanInfoRequest().getHumanInfoFeatures());
            newDimensionPropertyInfoRequest.setHumanInfoRequest(newHumanInfoRequest);

            PlaceInfoRequest newPlaceInfoRequest = new PlaceInfoRequest();
            newPlaceInfoRequest.setSalesGroup(e.getPlaceInfoRequest().getSalesGroup());
            newPlaceInfoRequest.setChannelCode(e.getPlaceInfoRequest().getChannelCode());
            newPlaceInfoRequest.setDepartmentCode(e.getPlaceInfoRequest().getDepartmentCode());
            newPlaceInfoRequest.setSalesDepartment(e.getPlaceInfoRequest().getSalesDepartment());
            newPlaceInfoRequest.setPriceArea(e.getPlaceInfoRequest().getPriceArea());
            newPlaceInfoRequest.setStorePlace(e.getPlaceInfoRequest().getStorePlace());
            newPlaceInfoRequest.setOrgSalesOrganizationCode(e.getPlaceInfoRequest().getOrgSalesOrganizationCode());
            newPlaceInfoRequest.setFactoryCode(e.getPlaceInfoRequest().getFactoryCode());
            newPlaceInfoRequest.setSalesArea(e.getPlaceInfoRequest().getSalesArea());
            newPlaceInfoRequest.setSalesUnitCode(e.getPlaceInfoRequest().getSalesUnitCode());
            newPlaceInfoRequest.setPlaceInfoFeatures(e.getPlaceInfoRequest().getPlaceInfoFeatures());
            newDimensionPropertyInfoRequest.setPlaceInfoRequest(newPlaceInfoRequest);
            newDimensionPropertyInfoRequestList.add(newDimensionPropertyInfoRequest);
        });
        newPriceQueryRequest.setDimensionPropertyInfoRequestList(newDimensionPropertyInfoRequestList);
    }

    /**
     * 价格查询请求
     * @param priceQueryRequest 查询请求
     */
    private void paramTrim(PriceQueryRequest priceQueryRequest) {
        for (DimensionPropertyInfoRequest dimensionPropertyInfoRequest : priceQueryRequest.getDimensionPropertyInfoRequestList()) {
            humanInfoTrim(dimensionPropertyInfoRequest.getHumanInfoRequest());
            placeInfoTrim(dimensionPropertyInfoRequest.getPlaceInfoRequest());
            materialInfoTrim(dimensionPropertyInfoRequest.getMaterialInfoRequest());
        }
    }

    /**
     * 货的信息
     * @param materialInfoRequest
     */
    private void materialInfoTrim(MaterialInfoRequest materialInfoRequest) {
        if (Objects.isNull(materialInfoRequest)) {
            return;
        }
        materialInfoRequest.setMaterialCode(transParam(materialInfoRequest.getMaterialCode()));
        materialInfoRequest.setScItemGroupCode(transParam(materialInfoRequest.getScItemGroupCode()));
    }

    /**
     * 场的信息
     * @param placeInfoRequest
     */
    private void placeInfoTrim(PlaceInfoRequest placeInfoRequest) {
        if(Objects.isNull(placeInfoRequest)){
            return;
        }
        placeInfoRequest.setOrgSalesOrganizationCode(transParam(placeInfoRequest.getOrgSalesOrganizationCode()));

        placeInfoRequest.setChannelCode(transParam(placeInfoRequest.getChannelCode()));

        placeInfoRequest.setSalesUnitCode(transParam(placeInfoRequest.getSalesUnitCode()));

        placeInfoRequest.setSalesArea(transParam(placeInfoRequest.getSalesArea()));

        placeInfoRequest.setFactoryCode(transParam(placeInfoRequest.getFactoryCode()));

        placeInfoRequest.setSalesDepartment(transParam(placeInfoRequest.getSalesDepartment()));

        placeInfoRequest.setSalesGroup(transParam(placeInfoRequest.getSalesGroup()));

        placeInfoRequest.setStorePlace(transParam(placeInfoRequest.getStorePlace()));

        placeInfoRequest.setDepartmentCode(transParam(placeInfoRequest.getDepartmentCode()));

        placeInfoRequest.setPriceArea(transParam(placeInfoRequest.getPriceArea()));
    }

    /**
     * 人相关信息trim
     * @param humanInfoRequest 人
     */
    private void humanInfoTrim(HumanInfoRequest humanInfoRequest) {
        if (Objects.isNull(humanInfoRequest)) {
            return;
        }
        humanInfoRequest.setCustomerCode(transParam(humanInfoRequest.getCustomerCode()));
        humanInfoRequest.setCustomerSendAddressCode(transParam(humanInfoRequest.getCustomerSendAddressCode()));
        humanInfoRequest.setCustomerSaleAddressCode(transParam(humanInfoRequest.getCustomerSaleAddressCode()));
        humanInfoRequest.setCustomerGroup(transParam(humanInfoRequest.getCustomerGroup()));
        humanInfoRequest.setPriceListCode(transParam(humanInfoRequest.getPriceListCode()));
    }

    /**
     * 转换参数
     * @return
     */
    public String transParam(String input){
        if (StringUtils.isNotBlank(input)) {
            return input.trim();
        }
        return "";
    }



    /**
     * 获取销售组织，销售部门、销售组内外部编码对应关系
     *
     * @param priceQueryRequest
     * @return
     */
    public Map<String, String> obtainSalesOrganizationMap(PriceQueryRequest priceQueryRequest) {

        //销售组织list
        List<String> salesOrganizationCodes = priceQueryRequest.getDimensionPropertyInfoRequestList().stream().map(item ->
                        item.getPlaceInfoRequest().getOrgSalesOrganizationCode()).collect(Collectors.toSet())
                .stream().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(salesOrganizationCodes)) {
            //销售组织编码必传，因为每个价格维度都有这个属性
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            log.error("销售组织编码不允许为空！= {}", JSONObject.toJSONString(priceQueryRequest));
            throw new FacadeException("OTS-07-006-01-15-007");
        }
        //销售部门list
        List<String> salesDepartmentCodes = priceQueryRequest.getDimensionPropertyInfoRequestList().stream().map(item ->
                        item.getPlaceInfoRequest().getSalesDepartment()).collect(Collectors.toSet())
                .stream().collect(Collectors.toList());
        //销售组list
        List<String> salesGroupCodes = priceQueryRequest.getDimensionPropertyInfoRequestList().stream().map(item ->
                        item.getPlaceInfoRequest().getSalesGroup()).collect(Collectors.toSet())
                .stream().collect(Collectors.toList());

        List<String> list = Lists.newArrayList();
        list.addAll(salesOrganizationCodes);
        list.addAll(salesDepartmentCodes);
        list.addAll(salesGroupCodes);

        //获取销售组织编码的对应关系（内部编码:外部编码）
        BaselineGetOrganizationByIds2Request baselineGetOrganizationByIds2Request = new BaselineGetOrganizationByIds2Request();
        baselineGetOrganizationByIds2Request.setIds(list);
        baselineGetOrganizationByIds2Request.setStatus(1);
        BaselineGetOrganizationByIds2Response baselineGetOrganizationByIds2Response = baseDataService.baselineGetOrganizationByIds2(baselineGetOrganizationByIds2Request);

        if (Objects.isNull(baselineGetOrganizationByIds2Response)) {
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            log.error("接口调用异常，请排查 com.epoch.app.bcots.service.BaseDataService.baselineGetOrganizationByIds()");
            throw new FacadeException("OTS-07-010-01-17-001");
        }
        List<OrganizationSDO> orgSalesOrganizationCodeResultList = baselineGetOrganizationByIds2Response.getResult();
        if (CollectionUtils.isEmpty(orgSalesOrganizationCodeResultList)) {
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            log.error("未查询到该销售组织对应的外部编码，请检查映射关系是否存在 = {}", list);
            throw new FacadeException("OTS-07-005-01-16-002");
        }
        return orgSalesOrganizationCodeResultList.stream().
                collect(Collectors.toMap(OrganizationSDO::getId, OrganizationSDO::getOutCode));

    }

    /**
     * 获取物料内外部编码对应关系
     *
     * @param priceQueryRequest
     * @return
     */
    public List<ScItemSDO> obtainItemMap(PriceQueryRequest priceQueryRequest, boolean innerCode) {
        //获取所有的物料编码
        List<String> materialCodeList = priceQueryRequest.getDimensionPropertyInfoRequestList().stream().filter(item ->
                        Objects.nonNull(item.getMaterialInfoRequest()) && StringUtils.isNotBlank(item.getMaterialInfoRequest().
                                getMaterialCode())).map(item -> item.getMaterialInfoRequest().getMaterialCode()).
                collect(Collectors.toSet()).stream().collect(Collectors.toList());

        if (CollectionUtils.isEmpty(materialCodeList)) {
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            log.error("物料编码不能为空 = {}", JSONObject.toJSONString(priceQueryRequest));
            throw new FacadeException("OTS-07-006-01-15-006");
        }


        //获取内外部物料编码的对应关系（内部编码:外部编码）
        SearchScItemRequest searchScItemRequest = new SearchScItemRequest();
        Map<String, Object> searchReqDTO = new HashMap<>();
        if (innerCode) {
            searchReqDTO.put("scItemIds", materialCodeList);
        } else {
            searchReqDTO.put("outerIdList", materialCodeList);
        }
        searchScItemRequest.setSearchReqDTO(searchReqDTO);

        log.info("获取物料内外部编码对应关系入参:"+ JSON.toJSONString(searchScItemRequest));
        //add by 皓晖 at 20211216 for 新建预报订单选择最近使用,超过20条货品时,不展示常规价格 begin
        searchScItemRequest.setPageSize(2000);
        //add by 皓晖 at 20211216 for 新建预报订单选择最近使用,超过20条货品时,不展示常规价格 end
        Result<List<ScItemSDO>> listResult = baseDataService.searchScItem(searchScItemRequest);
        log.info("获取物料内外部编码对应关系出参:"+ JSON.toJSONString(listResult));

        if (Objects.isNull(listResult)) {
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            log.error("接口调用异常，请排查 com.epoch.app.bcots.service.BaseDataService.searchScItem()");
            throw new FacadeException("OTS-07-010-01-17-001");
        }

        if (CollectionUtils.isEmpty(listResult.getResult())) {
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            log.error("未查询到该物料编码对应的外部编码，请检查映射关系是否存在 = {}", materialCodeList);
            throw new FacadeException("OTS-07-005-01-16-004");
        }

        return listResult.getResult();
    }

    /**
     * 获取业务渠道内外部编码对应关系
     *
     * @param priceQueryRequest
     * @return
     */
    public Map<String, String> obtainChannelMap(PriceQueryRequest priceQueryRequest) {

        Map<String, String> channelCodeMap = Maps.newHashMap();
        List<String> channelCodeList = priceQueryRequest.getDimensionPropertyInfoRequestList().stream().
                filter(item -> Objects.nonNull(item.getPlaceInfoRequest()) && StringUtils.isNotBlank(item.getPlaceInfoRequest().
                        getChannelCode())).map(item -> item.getPlaceInfoRequest().getChannelCode()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(channelCodeList)) {
            return channelCodeMap;
        }

        //获取销售渠道编码的对应关系（内部编码:外部编码）
        BaselineBatchQueryChannelsRequest baselineBatchQueryChannelsRequest = new BaselineBatchQueryChannelsRequest();
        baselineBatchQueryChannelsRequest.setChannelCodes(channelCodeList);
        Object channelResult = baseDataService.baselineBatchQueryChannels(baselineBatchQueryChannelsRequest);
        if (Objects.isNull(channelResult)) {
            log.error("接口调用异常，请排查 com.epoch.app.bcots.service.BaseDataService.baselineBatchQueryChannels()");
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            throw new FacadeException("OTS-07-010-01-17-001");
        }
        Map<String, Object> channelResultMap = (Map<String, Object>) channelResult;
        Map<String, Object> channelMap = (Map<String, Object>) channelResultMap.get("result");
        List<Map<String, Object>> channelList = (List<Map<String, Object>>) channelMap.get("result");
        if (CollectionUtils.isEmpty(channelList)) {
            log.error("查询的渠道不存在，请检查是否存在映射关系 = {}", priceQueryRequest.getDimensionPropertyInfoRequestList());
            log.error("PriceQueryServiceImpl#batchQueryPriceExpand_fail");
            throw new FacadeException("OTS-07-005-01-16-003");
        }
        if (CollectionUtils.isNotEmpty(channelList)) {
            channelList.stream().filter(item -> Objects.nonNull(item) && StringUtils.
                    isNotBlank((String) item.get("channelCode")) && StringUtils.isNotBlank((String) item.
                    get("outCode"))).forEach(item -> {
                channelCodeMap.put((String) item.get("channelCode"), (String) item.get("outCode"));
            });
        }

        return channelCodeMap;
    }


    @Override
    @FacadeInvoker(remark = "价格查询")
    public Result<PriceQueryResponse> batchQueryPrice(PriceQueryRequest request) {
        log.info("当前查询价格入参 = {}", JSONObject.toJSONString(request));
        PriceQueryResponse response = new PriceQueryResponse();
        List<PriceEntity> priceEntityList = PriceFactory.createPrice(request);
        if (CollectionUtils.isNotEmpty(priceEntityList)) {
            List<ItemPriceResponse> itemPriceResponseList = new ArrayList<>();
            priceEntityList.forEach(e -> {
                ItemPriceResponse itemPriceResponse = ItemPriceResponse.builder()
                        .itemId(e.getItemId())
                        .isNegativeFlag(e.obtainIsNegativeFlag())
                        .itemCount(e.obtainItemCount())
                        .isTitleFlag(e.obtainTitleFlag())
                        .moneyAmout(e.obtainMoneyAmout() == null ? -999 : e.obtainMoneyAmout())
                        .moneyPercentage(e.obtianMoneyPercentage())
                        .currency(e.obtainCurrency())
                        .caculatePattern(e.obtainCaculatePattern())
                        .priceUnit(e.obtainPriceUnit())
                        .isManualFlag(e.obtainIsManualFlag())
                        .queryFlag(e.obtainQueryFlag())
                        //追加日志
                        .features(e.getFeatures()).build();
                itemPriceResponseList.add(itemPriceResponse);
            });
            response.setItemPriceResponseList(itemPriceResponseList);
        }
        return Result.success(response);
    }

    @Override
    public Result<List<PriceDimensionSDO>> batchPriceDimension(PriceDimensionRequest request) {
        return priceQueryRepository.batchPriceDimension(request.getTableNames());
    }

    @FacadeInvoker
    @Override
    public Result<List<CustomerItemPriceResponse>> loadCustomerItemPrice(CustomerItemPriceRequest customerItemPriceRequest) {

        List<CustomerItemPriceResponse> priceDimensionSDOS = Lists.newArrayList();

        Result<List<CustomerItemPriceResponse>> result = Result.success(priceDimensionSDOS);


        //校验货品
        if (Objects.isNull(customerItemPriceRequest) || StringUtils.isBlank(customerItemPriceRequest.getItemCode())) {
            throw new FacadeException("OTS-07-005-01-15-013");
        }

        //校验价格类型
        if (Objects.isNull(customerItemPriceRequest) || StringUtils.isBlank(customerItemPriceRequest.getPriceType())) {
            throw new FacadeException("OTS-07-005-01-15-014");
        }

        //查询客户地址信息
        Result<List<CustomerAddress>> customerAddressDataResult = customerAddressRepository.pageQueryCustomerAddressData(customerItemPriceRequest);
        if (Objects.isNull(customerAddressDataResult) || CollectionUtils.isEmpty(customerAddressDataResult.getResult())) {
            return result;
        }

        result.setTotal(customerAddressDataResult.getTotal());

        List<CustomerAddress> customerAddresses = customerAddressDataResult.getResult();

        //查询客户信息
        List<String> customerCodeList = customerAddresses.stream().map(CustomerAddress::getCustomerCode).collect(Collectors.toList());

        CustomerBatchRequest customerBatchRequest = new CustomerBatchRequest();
        customerBatchRequest.setCodes(customerCodeList);
        List<CustomerSDO> customerSDOList = customerRepository.batchQuery(customerBatchRequest);
        Map<String,String> customerCodeAndNameMap = Maps.newHashMap();
        if(CollectionUtils.isNotEmpty(customerSDOList)){
            customerCodeAndNameMap = customerSDOList.stream().collect(Collectors.toMap(CustomerSDO::getCode,CustomerSDO::getName));
        }

        queryClientItemPrice(priceDimensionSDOS,customerAddresses,customerItemPriceRequest,customerCodeAndNameMap);

        return result;
    }


    public void queryClientItemPrice(List<CustomerItemPriceResponse> customerItemPriceResponses,
                                     List<CustomerAddress> customerAddresses,
                                     CustomerItemPriceRequest customerItemPriceRequest,
                                     Map<String, String> customerCodeAndNameMap) {

        //获取所有的销售组织编码和描述的映射关系
        List<String> saleOrganizationCodeList = customerAddresses.stream().map(CustomerAddress::getOrgSaleOrganizationCode).collect(Collectors.toList());
        Map<String, String> saleOrganizationCodeDescMap = propertyProcessManager.getPropertyProcess(DimensionPropertyEnum.ORG_SALES_ORGANIZATION_CODE.getKey())
                .obtainCodeAndDescMap(saleOrganizationCodeList, true);
        //获取所有的销售组织内外部编码的映射关系
        Map<String, String> saleOrganizationCodeMap = propertyProcessManager.getPropertyProcess(DimensionPropertyEnum.ORG_SALES_ORGANIZATION_CODE.getKey())
                .obtainInnerCodeAndOuterCodeMap(saleOrganizationCodeList, true);

        //获取所有的业务渠道编码和描述的映射关系
        List<String> channelCodeList = customerAddresses.stream().map(CustomerAddress::getChannelCode).collect(Collectors.toList());
        Map<String, String> channelCodeDescMap = propertyProcessManager.getPropertyProcess(DimensionPropertyEnum.CHANNEL_CODE.getKey())
                .obtainCodeAndDescMap(channelCodeList, true);
        //获取所有的业务渠道内外部编码的映射关系
        Map<String, String> channelCodeMap = propertyProcessManager.getPropertyProcess(DimensionPropertyEnum.CHANNEL_CODE.getKey())
                .obtainInnerCodeAndOuterCodeMap(channelCodeList, true);

        //获取货品的编码和描述的映射关系
        Map<String, String> itemCodeDescMap = propertyProcessManager.getPropertyProcess(DimensionPropertyEnum.MATERIAL_CODE.getKey())
                .obtainCodeAndDescMap(Lists.newArrayList(customerItemPriceRequest.getItemCode()), true);

        //获取货品的内外部编码的映射关系
        Map<String, String> itemCodeMap = propertyProcessManager.getPropertyProcess(DimensionPropertyEnum.MATERIAL_CODE.getKey())
                .obtainInnerCodeAndOuterCodeMap(Lists.newArrayList(customerItemPriceRequest.getItemCode()), true);


        //存储映射关系
        Map<String, CustomerAddress> customerAddressMap = Maps.newHashMap();
        for (CustomerAddress customerAddress : customerAddresses) {
            String key = UUID.randomUUID().toString();
            customerAddressMap.put(key, customerAddress);
        }


        //批量构建查询参数
        PriceQueryRequest priceQueryRequest = new PriceQueryRequest();
        List<DimensionPropertyInfoRequest> dimensionPropertyInfoRequestList = Lists.newArrayList();
        customerAddressMap.entrySet().forEach(e -> {
            String key = e.getKey();
            CustomerAddress value = e.getValue();

            DimensionPropertyInfoRequest request = new DimensionPropertyInfoRequest();
            request.setPriceTypeId(customerItemPriceRequest.getPriceType());
            request.setQueryFlag(key);
            request.setPriceUseDate(new Date());

            //构建货品的信息
            MaterialInfoRequest materialInfoRequest = new MaterialInfoRequest();
            materialInfoRequest.setMaterialCode(customerItemPriceRequest.getItemCode());
            materialInfoRequest.setScItemGroupCode("11");
            request.setMaterialInfoRequest(materialInfoRequest);

            //构建人的信息
            HumanInfoRequest humanInfoRequest = new HumanInfoRequest();
            humanInfoRequest.setCustomerCode(value.getCustomerCode());
            humanInfoRequest.setCustomerSendAddressCode(value.getAddressCode());
            humanInfoRequest.setCustomerSaleAddressCode(value.getCustomerCode());
            request.setHumanInfoRequest(humanInfoRequest);

            //构建场的信息
            PlaceInfoRequest placeInfoRequest = new PlaceInfoRequest();
            placeInfoRequest.setOrgSalesOrganizationCode(value.getOrgSaleOrganizationCode());
            placeInfoRequest.setSalesUnitCode("PC");
            placeInfoRequest.setChannelCode(value.getChannelCode());
            request.setPlaceInfoRequest(placeInfoRequest);
            dimensionPropertyInfoRequestList.add(request);
        });
        priceQueryRequest.setDimensionPropertyInfoRequestList(dimensionPropertyInfoRequestList);
        Map<String, String> features = Maps.newHashMap();
        features.put("codeFlag", "inner_code_to_out_code");
        priceQueryRequest.setFeatures(features);


        //批量查询价格
        Result<PriceQueryResponse> priceQueryResponseResult = null;
        try {
            priceQueryResponseResult = this.batchQueryPriceExpand(priceQueryRequest);
        } catch (Exception e) {
            log.error("查询价格失败 = {}", e);
            List<ItemPriceResponse> itemPriceResponseList = Lists.newArrayList();
            priceQueryRequest.getDimensionPropertyInfoRequestList().forEach(req -> {
                ItemPriceResponse itemPriceResponse = new ItemPriceResponse();
                itemPriceResponse.setQueryFlag(req.getQueryFlag());
                itemPriceResponse.setMoneyAmout(-999L);
                itemPriceResponseList.add(itemPriceResponse);

            });
        }

        if (Objects.isNull(priceQueryResponseResult)
                || CollectionUtils.isEmpty(priceQueryResponseResult.getResult().getItemPriceResponseList())) {
            return;
        }

        List<ItemPriceResponse> itemPriceResponseList = priceQueryResponseResult.getResult().getItemPriceResponseList();

        //获取返回值和入参的映射关系
        Map<String, ItemPriceResponse> itemPriceResponseMap = itemPriceResponseList.stream().collect(Collectors.toMap(ItemPriceResponse::getQueryFlag, Function.identity()));


        //获取入参和价格维度的对应关系
        Map<String, String> itemAndPriceDimensionMap = obtainItemAndPriceDimensionMap(itemPriceResponseMap);


        //填充价格和客户的映射关系
        customerAddressMap.entrySet().forEach(e -> {
            //用于映射入参和返回值的键
            String uuid = e.getKey();

            //客户的数据
            CustomerAddress customerAddress = e.getValue();

            //价格的数据
            ItemPriceResponse itemPriceResponse = itemPriceResponseMap.get(uuid);

            CustomerItemPriceResponse customerItemPriceResponse = new CustomerItemPriceResponse();

            customerItemPriceResponse.setItemName(itemCodeDescMap.get(customerItemPriceRequest.getItemCode())
                    + "(" + itemCodeMap.get(customerItemPriceRequest.getItemCode()) + ")");

            customerItemPriceResponse.setPriceAmount(new BigDecimal(itemPriceResponse.getMoneyAmout()
                    .toString()).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_DOWN)
                    .stripTrailingZeros().toPlainString());

            customerItemPriceResponse.setPriceType(PriceTypeEnum.ZP01.getDesc() + "(" + PriceTypeEnum.ZP01.getCode() + ")");
            customerItemPriceResponse.setCustomerSendDesc(customerAddress.getAddressName() + "(" + customerAddress.getAddressCode() + ")");

            customerItemPriceResponse.setCustomerDesc(customerCodeAndNameMap
                    .get(customerAddress.getCustomerCode()) + "(" + customerAddress.getCustomerCode() + ")");

            customerItemPriceResponse.setPriceDimension(itemAndPriceDimensionMap.get(uuid));

            customerItemPriceResponse.setSalesOrganizationDesc(saleOrganizationCodeDescMap
                    .get(customerAddress.getOrgSaleOrganizationCode()) + "(" + saleOrganizationCodeMap
                    .get(customerAddress.getOrgSaleOrganizationCode()) + ")");

            customerItemPriceResponse.setChannelDesc(channelCodeDescMap
                    .get(customerAddress.getChannelCode()) + "(" + channelCodeMap
                    .get(customerAddress.getChannelCode()) + ")");

            customerItemPriceResponses.add(customerItemPriceResponse);

        });

    }

    private Map<String, String> obtainItemAndPriceDimensionMap(Map<String, ItemPriceResponse> itemPriceResponseMap) {
        Map<String, String> itemAndPriceDimensionMap = Maps.newHashMap();
        //获取查询到的价格所对应的维度
        Map<String, String> priceDimensionMap = Maps.newHashMap();
        Set<String> dimensionIds = Sets.newHashSet();
        itemPriceResponseMap.entrySet().forEach(e -> {
            ItemPriceResponse priceResponse = e.getValue();
            Map<String, String> priceFeatures = priceResponse.getFeatures();
            if (MapUtils.isNotEmpty(priceFeatures)) {
                String dimensionId = priceFeatures.get("dimensionId");
                if (StringUtils.isNotBlank(dimensionId)) {
                    priceDimensionMap.put(e.getKey(), dimensionId);
                    dimensionIds.add(dimensionId);
                }
            }
        });

        if (CollectionUtils.isEmpty(dimensionIds)) {
            return itemAndPriceDimensionMap;
        }

        List<PriceDimensionSDO> priceDimensionSDOS = priceQueryRepository.queryPriceDimensionList(new ArrayList<>(dimensionIds));

        if (CollectionUtils.isEmpty(priceDimensionSDOS)) {
            return itemAndPriceDimensionMap;
        }

        Map<String, String> dimensionCodeAndDescMap = priceDimensionSDOS.stream()
                .collect(Collectors.toMap(PriceDimensionSDO::getDimensionId, PriceDimensionSDO::getDimensionDesc));

        priceDimensionMap.entrySet().forEach(e -> {
            itemAndPriceDimensionMap.put(e.getKey(), dimensionCodeAndDescMap.get(e.getValue()) + "(" + e.getValue() + ")");
        });

        return itemAndPriceDimensionMap;
    }


    @Override
    @FacadeInvoker
    public Result<List<RegularPriceResponse>> queryRegularPriceList(RegularPriceRequest regularPriceRequest) {

        // 控制角色
        EmployeeGetCurrentLoginResponse currentLoginEmployeeRoles = bcOtsService.employeeGetCurrentLogin();
        if (currentLoginEmployeeRoles != null && StringUtils.isNotBlank(currentLoginEmployeeRoles.getRoleCodes())){
            String roleCodes = currentLoginEmployeeRoles.getRoleCodes();
            if (StringUtils.isBlank(roleCodes) || "[]".equals(roleCodes)){
                return Result.success(new ArrayList<>());
            }
            List<String> noPermissionRoleCodeList = Lists.newArrayList(RoleCodeEnum.SALE_MAN.getCode(), RoleCodeEnum.DEPARTMENT_MANAGER.getCode());
            String newRoleCodes = roleCodes.replaceAll(" ", "");
            List<String> roles = com.alibaba.acm.shaded.com.google.common.collect.Lists.newArrayList(newRoleCodes.substring(1, newRoleCodes.length() - 2).split(","));
            boolean permission = false;
            for (String role : roles) {
                if (!noPermissionRoleCodeList.contains(role)) {
                    permission = true;
                    break;
                }
            }
            if (!permission){
                return Result.success(new ArrayList<>());
            }
        }

        return priceQueryRepository.loadRegularPriceList(regularPriceRequest);
    }
}
